﻿using System;
using System.Collections.Generic;
using System.Threading;
using SDT.Libraries.Utilities;

namespace SDT.ServiceSystem
{
    public delegate bool WorkResultHandlerDelegate(IWorkUnit WorkUnit);

    /// <summary>
    /// Written by SinhNT
    /// </summary>
    public abstract class WorkerThread : IWorkerThread
    {
        private static int UniversalId = 0;

        #region Data Fields
        private int id = 0;
        public int Id
        {
            get { return id; }
        }

        private string name = "WorkerThread";
        public string Name
        {
            get { return name; }
            set { name = value == null ? "WorkerThread" : value.Trim(); }
        }

        public virtual int Interval
        {
            get { return Convert.ToInt32(Res.Resources.Interval); }
        }

        public virtual int WorkUnitInterval
        {
            get { return Convert.ToInt32(Res.Resources.WorkUnitInterval); }
        }

        public virtual string ConnectionString
        {
            get { return Res.Resources.ConnectionString; }
        }
        #endregion

        protected LogHelper Logger = new LogHelper(Res.Resources.LogFile);
      

        #region Works list
        private Queue<IWorkUnit> MyWorks = new Queue<IWorkUnit>();

        public IWorkUnit GetWork()
        {
            lock (MyWorks)
                return MyWorks.Count > 0 ? MyWorks.Dequeue() : null;
        }

        public void AddWork(IWorkUnit newWork)
        {
            lock (MyWorks)
                MyWorks.Enqueue(newWork);
        }

        public void ClearWork()
        {
            lock (MyWorks)
                MyWorks.Clear();
        }

        public bool HaveWork
        {
            get { lock (MyWorks) return MyWorks.Count > 0; }
        }

        public int WorkSize
        {
            get { lock (MyWorks) return MyWorks.Count; }
        }
        #endregion

        #region Constructors
        public WorkerThread()
        {
            id = Interlocked.Increment(ref UniversalId);

            #region Create worker-thread
            TheThread = new Thread(new ThreadStart(DoWork));
            TheThread.IsBackground = true;
            #endregion
        } 
        #endregion

        protected virtual bool CanStop
        {
            get { return HaveWork; }
        }

        protected virtual void LoadCache() { }
        protected virtual void SaveCache() { }

        #region Worker thread
        protected Thread TheThread = null;

        public abstract void DoWork();

        public virtual void StartWorking()
        {
            LoadCache();
            lock (TheThread)
            {
                Logger.AddEntry(string.Format("StartWorking [{0}]", id));
                Logger.AddEntry(string.Format("From state = {0}", TheThread.ThreadState), 1);

                //if (HaveWork)
                //{
                    if (ThreadState.Unstarted == (TheThread.ThreadState & ThreadState.Unstarted))
                        TheThread.Start();
                    else// if (ThreadState.Stopped == (TheThread.ThreadState & ThreadState.Stopped))
                    {
                        TheThread = new Thread(new ThreadStart(DoWork));
                        TheThread.IsBackground = true;
                        TheThread.Start();
                    }
                //}

                Logger.AddEntry(string.Format("To state = {0}", TheThread.ThreadState), 1);
            }
        }

        public virtual bool StopWorking()
        {
           // Logger.AddEntry(string.Format("StopWorking [{0}] - CanStop = {1}", id, CanStop));
            if (CanStop)
            {
                if (TheThread.IsAlive)
                    TheThread.Abort();

                SaveCache();
                //Logger.Flush();    

                return true;
            }
            
            return false;
        }
        #endregion

        private WorkResultHandlerDelegate resultHandler = null;
        public virtual WorkResultHandlerDelegate ResultHandler
        {
            set { lock(TheThread) resultHandler = value; }
            protected get { return resultHandler; }
        }
    }
}